package com.wuxx.quartz;

import com.wuxx.quartz.model.CronTimingModel;
import com.wuxx.quartz.model.IntervalTimingMode;
import com.wuxx.quartz.model.TimingModel;
import com.wuxx.quartz.trigger.TriggerManager;
import org.nutz.integration.quartz.QuartzJob;
import org.nutz.integration.quartz.QuartzManager;
import org.nutz.integration.quartz.QuartzManagerImpl;
import org.nutz.ioc.loader.annotation.IocBean;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 定时任务配置
 * @author wuxx
 * @date 2022/03/11 10:07
 */
@IocBean(name = "quartzTaskManager",args = {"refer:scheduler","refer:triggerManager","refer:quartzManager"})
public class QuartzTaskManager extends QuartzManagerImpl {
    /**
     * 获取日志记录器Logger，名字为本类类名
     */
    private static Logger log = LogManager.getLogger(QuartzTaskManager.class);

    protected final QuartzManager quartzManager;
    protected final Scheduler scheduler;

    protected final Boolean initStatus;

    protected final TriggerManager triggerManager;

    private static QuartzTaskManager taskManager;

    public QuartzTaskManager(Scheduler scheduler, TriggerManager triggerManager, QuartzManager quartzManager) {
        this.quartzManager = quartzManager;
        this.scheduler = scheduler;
        taskManager = this;
        boolean status = true;
        try {
            //全局绑定，所有的job在被调度的时候都会被监听
//            scheduler.getListenerManager().addJobListener(new QuartzListener(), EverythingMatcher.allJobs());
//            log.info("-------------------------------------------------------------");
//            log.info("-------------------------------------------------------------");
//            log.info("----------------quartzListener 任务监听已注册-------------------");
//            log.info("-------------------------------------------------------------");
//            log.info("-------------------------------------------------------------");
            // 启动调度器
            scheduler.start();
            log.info("-------------------------------------------------------------");
            log.info("-------------------------------------------------------------");
            log.info("-------------------defaultTaskJob start----------------------");
            log.info("-------------------------------------------------------------");
            log.info("-------------------------------------------------------------");

        } catch (SchedulerException e) {
            log.error("定时器调度器启动失败，定时器不可用！", e);
            status = false;
        }
        initStatus = status;
        this.triggerManager = triggerManager;
    }

    public static QuartzTaskManager getInstance(){
        return taskManager;
    }


    /**
     * 添加定时任务
     *
     * @param timingModel 任务model
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public Date addTask(TimingModel timingModel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, SchedulerException {
        checkTimingInit();
        // 构建任务信息
        JobDetail jobDetail = JobBuilder.newJob(timingModel.getTaskClass().getDeclaredConstructor().newInstance().getClass())
                .withDescription(timingModel.getDescription())
                .withIdentity(timingModel.getTaskName(), timingModel.getGroupName())
                .build();
        // 构建触发器
        Trigger trigger = triggerManager.build(timingModel);
        // 将任务参数放入触发器中
        if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) {
            trigger.getJobDataMap().putAll(timingModel.getParam());
        }
        QuartzJob quartzJob = new QuartzJob(jobDetail.getKey(),trigger,jobDetail);

        // 启动任务
        quartzManager.add(quartzJob);
        return trigger.getNextFireTime();
    }


    /**
     * 执行一次任务
     *
     * @param intervalTimingMode 任务model
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public Date addOnceTask(IntervalTimingMode intervalTimingMode) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, SchedulerException {
        intervalTimingMode.setRepeatCount(0);
        return this.addTask(intervalTimingMode);
    }



    /**
     * 更新任务，任务的标示（由taskName和groupName组成）不变，任务的触发器（触发频率）发生变化
     *
     * @param timingModel 任务model
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void updateTask(TimingModel timingModel) throws SchedulerException {
        // 获取到任务
        TriggerKey triggerKey = TriggerKey.triggerKey(timingModel.getTaskName(), timingModel.getGroupName());

        // 构建触发器
        Trigger trigger = triggerManager.build(timingModel);
        // 将任务参数放入触发器中
        if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) {
            trigger.getJobDataMap().putAll(timingModel.getParam());
        }
        // 将新的触发器绑定到任务标示上重新执行
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 更新任务参数
     *
     * @param taskName  任务名
     * @param groupName 任务组名
     * @param param     参数
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void updateTask(String taskName, String groupName, Map<String, Object> param) throws SchedulerException {
        // 获取到任务
        TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName);
        Trigger trigger = scheduler.getTrigger(triggerKey);

        //修改参数
        trigger.getJobDataMap().putAll(param);

        // 将新的触发器绑定到任务标示上重新执行
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 删除任务
     *
     * @param taskName  任务名
     * @param groupName 任务组
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void deleteTask(String taskName, String groupName) throws SchedulerException {
        // 暂停任务对应的触发器
        scheduler.pauseTrigger(TriggerKey.triggerKey(taskName, groupName));
        // 删除任务对应的触发器
        scheduler.unscheduleJob(TriggerKey.triggerKey(taskName, groupName));
        // 删除任务
        scheduler.deleteJob(JobKey.jobKey(taskName, groupName));
    }

    /**
     * 暂停任务
     *
     * @param taskName  添加任务时timingMode中的taskName
     * @param groupName 添加任务时timingMode中的groupName
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void pauseTask(String taskName, String groupName) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(taskName, groupName));
    }


    /**
     * 将暂停的任务恢复执行
     *
     * @param taskName  添加任务时timingMode中的taskName
     * @param groupName 添加任务时timingMode中的groupName
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void resumeTask(String taskName, String groupName) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(taskName, groupName));
    }

    /**
     * 启动所有任务
     *
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public void startAllTasks() {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭定时任务，回收所有的触发器资源
     *
     * @author YuanXiaohan
     * @date 2021/12/16 3:26 下午
     */
    public void shutdownAllTasks() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void setInitStatus() {
        try {
            //初始化所有定时任务
            scheduler.clear();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取所有的任务,暂时无法获取到任务执行类和任务描述
     *
     * @return java.util.List<org.demo.quartz.mode.TimingModel>
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    public List<TimingModel> getTaskList() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<TimingModel> taskList = new ArrayList<>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                TimingModel timingModel;
                if (trigger instanceof CronTrigger) {
                    timingModel = new CronTimingModel(null, jobKey.getName(), jobKey.getGroup(), null, ((CronTrigger) trigger).getCronExpression());
                    timingModel.setTaskStatus(scheduler.getTriggerState(trigger.getKey()).name());
                    taskList.add(timingModel);
                } else {
                    log.warn("name:"+jobKey.getName()+",group:"+jobKey.getGroup()+"的定时任务类型未知，请拓展QuartzTaskManager.getTaskList的任务类型解析");
                }
            }
        }
        return taskList;
    }

    /**
     * 获取当前任务状态
     * @param jobName 任务名称
     * @param groupName 任务分组
     * @return String
     * @throws SchedulerException 异常
     */
    public String getStatusName(String jobName,String groupName) {
        if(exist(jobName,groupName)){
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);
            try {
                return getTriggerStatesCn(scheduler.getTriggerState(triggerKey).name());
            } catch (SchedulerException e) {
                log.error(jobName+"获取当前任务状态异常");
            }
            return getTriggerStatesCn("ERROR");
        }
        return "0";
    }


    public Boolean exist(String jobName,String groupName) {
        try {
            return scheduler.checkExists(new JobKey(jobName, groupName));
        } catch (SchedulerException e) {
            log.error(jobName+"验证任务是否存在异常");
        }
        return false;
    }
    /**
     * 校验定时调度器是否初始化完成
     *
     * @author wuxx
     * @date 2022/06/07 2:28 下午
     */
    private void checkTimingInit() {
        if (!initStatus) {
            throw new RuntimeException("定时器未初始化，添加定时器失败!");
        }
    }


    private static String getTriggerStatesCn(String key) {
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("BLOCKED", "5");
        map.put("COMPLETE", "4");
        map.put("ERROR", "3");
        map.put("NONE", "-1");
        map.put("NORMAL", "1");
        map.put("PAUSED", "2");
        map.put("5", "阻塞");
        map.put("4", "完成");
        map.put("3", "出错");
        map.put("-1", "不存在");
        map.put("1", "正常");
        map.put("2", "暂停");
        map.put("0", "停止");
        return map.get(key);
    }


}
